package com.wisdytech.common.netty;

import com.wisdytech.linkdcs.configuration.dto.ConfigurationEqDto;
import com.wisdytech.linkdcs.configuration.service.ITtEqConfigurationDataService;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.concurrent.ImmediateEventExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.net.InetSocketAddress;
import java.util.Iterator;
import java.util.List;

/**
 * websocket server
 */
@Component
public class WebSocketServer {

    private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);


    @Value("${websocket.url}")
    private String webSocketUri;

    @Autowired
    private ITtEqConfigurationDataService configurationDataService;

    private final ChannelGroup channelGroup = new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE);
    private final EventLoopGroup bossGroup = new NioEventLoopGroup();
    private final EventLoopGroup workGroup = new NioEventLoopGroup();
    private Channel channel;

    public ChannelFuture start(InetSocketAddress address) {
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup, workGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new WebSocketServerHandlerInitializer(channelGroup, webSocketUri))
                //对应的是tcp/ip协议listen函数中的backlog参数 函数listen(int socketfd,int backlog)用来初始化服务端可连接队列
                //backlog参数指定了队列的大小
                .option(ChannelOption.SO_BACKLOG, 128)
                .childOption(ChannelOption.SO_KEEPALIVE, true);

        ChannelFuture future = bootstrap.bind(address).syncUninterruptibly();
        channel = future.channel();
        return future;
    }

    public void destroy() {
        if (channel != null) {
            channel.close();
        }
        channelGroup.close();
        workGroup.shutdownGracefully();
        bossGroup.shutdownGracefully();
    }

    /**
     * 推送设备数据
     */
    @Scheduled(cron = "*/10 * * * * ?")
    public void sendEqParamValue() {
        Iterator<Channel> channels = channelGroup.iterator();
        while (channels.hasNext()) {
            Channel channel = channels.next();
            String id = channel.attr(HttpRequestHandler.ZUTAIID).get();
            log.info("start write data to channel[{}]. zutaiId[{}]",channel.id(), id);
            List<ConfigurationEqDto> eqDtos = configurationDataService.getEquipmentRealData(id);
            configurationDataService.pushEquipmentData(eqDtos, channel);
        }
    }

}
